﻿using System;
using Tao.OpenGl;

namespace Aeon.Framework
{

/// <summary>
/// Material properties class.
/// Contains texture, color, and lighting information.
/// 
/// [TODO] Make list of colors, textures?
/// [TODO] Internal storage as float[].
/// </summary>
public class AeonMaterial
    {
    // --- Attributes:

    private IColor color;           // Material colors.
    private ITexture texture;       // Material textures.

    private Boolean mirror;         // Flag to apply lighting to both faces, or front face.

    private Int32 shininess;        // Shininess specular exponent component. Range 0...128.
    private IColor ambient;         // Ambient reflectance RGBA components. Range -1...1, default is (0.2,0.2,0.2,1.0).
    private IColor diffuse;         // Diffuse reflectance RGBA components. Range -1...1, default is (0.8,0.8,0.8,1.0).
    private IColor specular;        // Specular reflectance RGBA components. Range -1...1, default is (0,0,0,1).
    private IColor emission;        // Emitted light intensity RGBA components. Range -1...1, default is (0,0,0,1).

    // --- Properties:

    public IColor Color { get { return(color); } set { color = value; } }
    public ITexture Texture { get { return(texture); } set { texture = value; } }

    public Boolean Mirror { get { return(mirror); } set { mirror = value; } }

    public Int32 Shininess { get { return(shininess); } set { shininess = value; } }
    public IColor Ambient { get { return(ambient); } set { ambient = value; } }
    public IColor Diffuse { get { return(ambient); } set { ambient = value; } }
    public IColor Specular { get { return(ambient); } set { ambient = value; } }
    public IColor Emission { get { return(ambient); } set { ambient = value; } }

    private Single[] VectorAmbient  { get { return(new float[]{ ambient.R, ambient.G, ambient.B, ambient.A }); } }
    private Single[] VectorDiffuse  { get { return(new float[]{ diffuse.R, diffuse.G, diffuse.B, diffuse.A }); } }
    private Single[] VectorSpecular { get { return(new float[]{ specular.R, specular.G, specular.B, specular.A }); } }
    private Single[] VectorEmission { get { return(new float[]{ emission.R, emission.G, emission.B, emission.A }); } }

    // --- Constructor:

    /// <summary>
    /// One Constructor to rule them all, One Constructor to find them,
    /// One Constructor to bring them all, and in the darkness bind them,
    /// In the Land of Bytecode, where the Bits lie.
    /// 
    /// </summary>
    public AeonMaterial(Int32 shi, AeonColor amb, AeonColor dif, AeonColor spc, AeonColor emi, Boolean mirrored)
        {
        color = AeonColors.Default;
        texture = AeonTexture.None;

        mirror = mirrored;
        
        shininess = shi;
        ambient = amb;
        diffuse = dif;
        specular = spc;
        emission = emi;
        }

    // --- Public Methods:

    /// <summary>
    /// Applies material properties.
    /// Requires an active OpenGL context.
    /// 
    /// </summary>
    public void Apply()
        {
        int face = (mirror) ? (Gl.GL_FRONT_AND_BACK):(Gl.GL_FRONT);
        
        Gl.glMaterialfv(face, Gl.GL_AMBIENT, VectorAmbient);
        Gl.glMaterialfv (face, Gl.GL_DIFFUSE, VectorDiffuse);
        Gl.glMaterialfv(face, Gl.GL_SPECULAR, VectorSpecular);
        Gl.glMateriali(face, Gl.GL_SHININESS, shininess);
        
        // [TODO] Incomplete.
        }

    }


}
